package com.creaylei.stock.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.creaylei.stock.converter.StockPoConverter;
import com.creaylei.stock.dto.ExportQueryDto;
import com.creaylei.stock.dto.ExportStockDto;
import com.creaylei.stock.po.StockPo;
import com.creaylei.stock.service.WeeklyService;
import com.creaylei.stock.utils.ExcelUtil;
import com.creaylei.stock.utils.TimeUtil;
import com.gargoylesoftware.htmlunit.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.*;

/**
 * @Author zhang lei
 * @Date 2022-02-28 11:14
 */
@Slf4j
@Service
public class WeeklyServiceImpl implements WeeklyService {

    private static final String uri = "http://push2.eastmoney.com/api/qt/stock/get?ut=fa5fd1943c7b386f172d6893dbfba10b&fltt=2&invt=2&fields=f120,f121,f122,f174,f175,f59,f163,f43,f57,f58,f169,f170,f46,f44,f51,f168,f47,f164,f116,f60,f45,f52,f50,f48,f167,f117,f71,f161,f49,f530,f135,f136,f137,f138,f139,f141,f142,f144,f145,f147,f148,f140,f143,f146,f149,f55,f62,f162,f92,f173,f104,f105,f84,f85,f183,f184,f185,f186,f187,f188,f189,f190,f191,f192,f107,f111,f86,f177,f78,f110,f262,f263,f264,f267,f268,f255,f256,f257,f258,f127,f199,f128,f198,f259,f260,f261,f171,f277,f278,f279,f288,f152,f250,f251,f252,f253,f254,f269,f270,f271,f272,f273,f274,f275,f276,f265,f266,f289,f290,f286,f285,f292,f293,f294,f295&secid=%s&cb=jQuery112406117634654886226_1646403552413&_=1646403552414";

    public static final Map<String, String> dreamMarketValue = Map.of(
            "00700","36000, 80000",  //腾讯
            "002304", "2100, 5000",     //洋河
            "601225", "1225, 2600",   //陕西煤业
            "002027", "830, 1980", //分众
            "200596", "500, 1150" //古井贡B
    );

    public static final Map<String, Map<String, String>> dream = JSON.parseObject("{\"腾讯控股\":{\"三年后估值\":\"57000±10%\",\"理想买点\":\"<28500\",\"1年内卖点\":\"60000\"},\"贵州茅台\":{\"三年后估值\":\"30000±10%\",\"理想买点\":\"<15000\",\"1年内卖点\":\"35000\"},\"洋河股份\":{\"三年后估值\":\"4200±10%\",\"理想买点\":\"<2100\",\"1年内卖点\":\"5500\"},\"分众传媒\":{\"三年后估值\":\"①\",\"理想买点\":\"<830\",\"1年内卖点\":\"1980\"},\"古井贡Ｂ\":{\"三年后估值\":\"1100±10%\",\"理想买点\":\"<550\",\"1年内卖点\":\"1260\"},\"美的集团\":{\"三年后估值\":\"\",\"理想买点\":\"<4000\",\"1年内卖点\":\"12000\"},\"海康威视\":{\"三年后估值\":\"6200±10%\",\"理想买点\":\"<3120\",\"1年内卖点\":\"8400\"}}", Map.class);

    public static void main(String[] args) {
        Map<String, Map<String, String>> map = new HashMap<>();
        map.put("01000", Map.of("理想市值", "11111"));
        map.put("01001", Map.of("理想市值", "11111"));
        System.out.println(JSON.toJSONString(map));
    }

    // A = 3年后合理估值 = 3年后净利润 x (25 ~ 30)
    // 理想买点  A / 2 , 高杠杆打七折
    // 理想卖点  今年50PE || A X 150%
    //这里隐含了一个 今年50PE卖出，存款4% 三年也能达到 A x 150%



    // 如分钟 2022年预估 10年平均40 亿，  40 x (25 -30 ) ≈ 1100 ± 10%
    //理想卖点   三年后合理估值上限的 150%  || 三年后净利润 x50 pe ， 取孰低 为卖点

    @Override
    public List<StockPo> queryNewestInfo(List<String> codes, Double exchange, Integer cash) {
        if(CollectionUtils.isEmpty(codes)) {
            return new ArrayList<>();
        }

        //1. 锁定网站，根据code查询数据
        List<StockPo> stockPos = getEachInfo2(codes, exchange);
        Double sum = stockPos.stream().mapToDouble(StockPo::getExist).sum();
        if(cash !=null) {
            sum = sum+cash;
        }
        Double finalSum = sum;
        stockPos.forEach(s->{
            s.setRateDouble(s.getExist()/ finalSum);
            s.setRate(numberFormat(s.getRateDouble()));

            Map<String, String> map = dream.get(s.getName());
            if(MapUtils.isNotEmpty(map)) {
                s.setDreamMarketValue(map.get("理想买点"));
                s.setThisYearSellValue(map.get("1年内卖点"));
                s.setThreeYearValue(map.get("三年后估值"));
            }
        });

        stockPos.sort(Comparator.comparing(StockPo::getRateDouble).reversed());
        //2. 计算比例
        return stockPos;
    }

    @Override
    public void export(HttpServletResponse response, ExportQueryDto exportQueryDto) {
        List<StockPo> stockPos = queryNewestInfo(exportQueryDto.getCodes(), exportQueryDto.getExchangeRate(),exportQueryDto.getCash());
        if(!CollectionUtils.isEmpty(stockPos)) {
            StockPoConverter converter = new StockPoConverter();
            List<ExportStockDto> exportStockDtos = new ArrayList<>(stockPos.size());
            for (StockPo stockPo : stockPos) {
                exportStockDtos.add(converter.convertToDto(stockPo));
            }
            try {
                ExcelUtil.exportExcel(exportStockDtos, TimeUtil.dateToDateString(new Date()),
                        ExportStockDto.class, "个人持仓" ,response);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
            }
        }
    }

    private String numberFormat(double v) {
        NumberFormat nf = java.text.NumberFormat.getPercentInstance();
        nf.setMinimumFractionDigits(2);// 小数点后保留几位
        return nf.format(v);
    }

    /**
     * 换个接口
     * @param codes
     * @return
     */
    private List<StockPo> getEachInfo2(List<String> codes, Double exchange) {
        List<StockPo> result = new ArrayList<>(codes.size());
        for (String code : codes) {
            String oCode = code.split(" ")[0];
            String oNum = code.split(" ")[1];
            StockPo stockPo = getOneInfoPrice2(oCode);
            if(stockPo.getName().equals("腾讯控股")) {
                stockPo.setPrice(String.valueOf(Double.valueOf(stockPo.getPrice())*exchange));
            }else if(stockPo.getCode().equals("200596")) {
                stockPo.setPrice(String.valueOf(Double.valueOf(stockPo.getPrice())*exchange));
            }
            stockPo.setExist(Double.parseDouble(stockPo.getPrice()) * Integer.parseInt(oNum));
            stockPo.setCount(oNum);
            result.add(stockPo);
        }
        return result;
    }

    private StockPo getOneInfoPrice2(String code) {
        String url = String.format(uri, code);

        WebClient webClient = new WebClient(BrowserVersion.CHROME);
        //方便的方法来构建一个URL并将其加载到当前的WebWindow中
        WebResponse response = null;
        try {
            Page page = webClient.getPage(url);
            //返回最初用于创建此页的web响应
            response = page.getWebResponse();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (FailingHttpStatusCodeException e) {
            e.printStackTrace();
        }
        //使用服务器响应中指定的字符集/编码，以字符串形式返回响应内容。
        String result ;
        if(StringUtils.isEmpty( result = response.getContentAsString())) {
            log.warn("查询数据为空:{}", code);
            return null;
        }
        String temp = result.split("\\(")[1];
        JSONObject json = JSON.parseObject(temp.substring(0, temp.length()-2));
        JSONObject data = json.getJSONObject("data");
        log.info("查询code:{},数据:{}",code, data);
        StockPo stockPo = new StockPo();
        stockPo.setName(Optional.of(data.getString("f58")).orElse(""));
        stockPo.setCode(Optional.of(data.getString("f57")).orElse(""));
        //f39, f43
        stockPo.setPrice(data.getString("f43"));
        //f116 总值, f117流值
        stockPo.setMarketValue(StringUtils.isEmpty(data.getString("f116")) || data.getString("f116").equals("-")? "0": String.valueOf(Double.valueOf(data.getString("f116"))/100000000));
        //今年涨幅
        stockPo.setThisYearIncrease(data.getString("f122")+"%");
        return stockPo;
    }

    /**
     * http://push2his.eastmoney.com/api/qt/stock/kline/get?fields1=f1%2Cf2%2Cf3%2Cf4%2Cf5%2Cf6&fields2=f51%2Cf52%2Cf53%2Cf54%2Cf55%2Cf56%2Cf57%2Cf58%2Cf59%2Cf60%2Cf61&
     * klt=101&fqt=1&secid=0.000001&beg=0&end=20500000
     *
     * @param codes
     * @return
     */
    private List<StockPo> getEachInfo(List<String> codes) {
        StringBuilder uri = new StringBuilder("http://push2his.eastmoney.com/api/qt/stock/kline/get?fields1=f1%2Cf2%2Cf3%2Cf4%2Cf5%2Cf6&fields2=f51%2Cf52%2Cf53%2Cf54%2Cf55%2Cf56%2Cf57%2Cf58%2Cf59%2Cf60%2Cf61");

        //101是日K， 102是周K
        uri.append("&klt=").append(101);
        uri.append("&fqt=").append(1);


        List<StockPo> result = new ArrayList<>(codes.size());
        for (String code : codes) {
            uri.append("&secid=0.").append(code);
            //2000 前4位表示年份
            uri.append("&beg=").append(20220000);
            uri.append("&end=").append(20500000);
            StockPo stockPo = getOneInfoPrice(uri.toString());
            if (stockPo!=null) {
                result.add(stockPo);
            }
        }
        return result;
    }

    /**
     * 获取 名称，code， 收盘
     * @param uri
     * @return
     */
    private StockPo getOneInfoPrice(String uri) {
        StockPo stockPo = new StockPo();
        //使用指定的BrowserVersion创建web客户端实例。
        WebClient webClient = new WebClient(BrowserVersion.CHROME);
        String url = "http://push2his.eastmoney.com/api/qt/stock/kline/get?fields1=f1%2Cf2%2Cf3%2Cf4%2Cf5%2Cf6&fields2=f51%2Cf52%2Cf53%2Cf54%2Cf55%2Cf56%2Cf57%2Cf58%2Cf59%2Cf60%2Cf61&klt=101&fqt=1&secid=0.000003&beg=0&end=20500000";
        //方便的方法来构建一个URL并将其加载到当前的WebWindow中
        WebResponse response = null;
        try {
            Page page = webClient.getPage(uri);
        //返回最初用于创建此页的web响应
            response = page.getWebResponse();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (FailingHttpStatusCodeException e) {
            e.printStackTrace();
        }
        //使用服务器响应中指定的字符集/编码，以字符串形式返回响应内容。
        String result ;
        if(StringUtils.isEmpty( result = response.getContentAsString())) {
            log.warn("查询数据为空:{}", uri);
            return null;
        }
        JSONObject json = JSON.parseObject(result);
        JSONObject data = json.getJSONObject("data");

        stockPo.setName(data.getString("name"));
        stockPo.setCode(data.getString("code"));
        //开盘、收盘、最高、最低
        String[] newestInfo = getNewestInfo(data.getJSONArray("klines"));
        log.info("时间:{}, 开盘:{}, 收盘:{}, 最高:{}, 最低:{}",newestInfo[0],newestInfo[1],newestInfo[2],newestInfo[3],newestInfo[4]);
        //最新一天收盘价
        stockPo.setPrice(newestInfo[2]);
        return stockPo;
    }

    private String[] getNewestInfo(JSONArray klines) {
        return klines.get(klines.size()-1).toString().split(",");
    }
}
